package edu.indiana.d2i.vmm.policy;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

// one job can use only one software framework!!!
public class SoftwareConstraintMgr implements ConstraintsManager {
	private static final Log logger = LogFactory
			.getLog(SoftwareConstraintMgr.class);

	static class SoftwareFramework {
		public String name;
		public String licenseInfo;
		public int maxInstanceNum = 0;
		public List<String> imageIDList = new ArrayList<String>();
		public int runningInstanceNum = 0;

	}
	
	// <software_name, software_object>
	private Map<String, SoftwareFramework> softwares = new HashMap<String, SoftwareFramework>();

	// should add error checking!!
	private void loadConfig() throws Exception {
		InputStream inStream = getClass().getClassLoader().getResourceAsStream(
		"vmm-image.xml");
		DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
			Document doc = docBuilder.parse(inStream);
			Element root = doc.getDocumentElement();
			NodeList nodelist = root.getElementsByTagName("image");
			for (int i = 0; i < nodelist.getLength(); i++) {
				Element elem = (Element)nodelist.item(i);
				String id = elem.getElementsByTagName("id").item(0).getFirstChild().getNodeValue();
				String framework = elem.getElementsByTagName("framework").item(0).getFirstChild().getNodeValue();
				String maxnum = elem.getElementsByTagName("maxnum").item(0).getFirstChild().getNodeValue();
				if (softwares.containsKey(framework)) {
					softwares.get(framework).imageIDList.add(id);
				} else {
					SoftwareFramework software = new SoftwareFramework();
					software.maxInstanceNum = Integer.valueOf(maxnum);
					software.imageIDList.add(id);
					softwares.put(framework, software);
				}
			}
		} catch (Exception e) {
			logger.error(e);
			throw e;
		} 
	}
	
	// should move this into a Configuration class
	public SoftwareConstraintMgr() throws Exception {
		loadConfig();
	}
	
	@Override
	public String requestImage(String softwareFramework, int instanceNum) {
		synchronized (softwares) {			
			String imageID = null;
			if (softwares.containsKey(softwareFramework)) {
				SoftwareFramework software = softwares.get(softwareFramework);
				if (software.maxInstanceNum < 0) imageID = software.imageIDList.get(0);  
				else if ((software.runningInstanceNum + instanceNum) > software.maxInstanceNum) {
					logger.info(softwareFramework
							+ " cannot allow more instances to run");
				} else {
					software.runningInstanceNum += instanceNum; // change status
					imageID = software.imageIDList.get(0);
				}
			} else {
				logger.error("No such software framework " + softwareFramework);
			}

			return imageID;
		}
	}

	@Override
	public void releaseImage(String softwareFramework, int instanceNum) {
		synchronized (softwares) {
			if (softwares.containsKey(softwareFramework)) {
				SoftwareFramework software = softwares.get(softwareFramework);
				software.runningInstanceNum -= instanceNum;
			} else {
				logger.error("Cannot release image. No such software framework "
						+ softwareFramework);
			}
		}
	}
}
